﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;

namespace SimpleIR
{
	/// <summary>
	/// Abstract base type to represent all invocation signatures.
	/// </summary>
	public abstract class IRInvokeSig
	{
		/// <summary>
		/// The base name for the method.
		/// </summary>
		public readonly string InvokeName;

		/// <summary>
		/// The list of argument types for the method.
		/// </summary>
		public readonly List<IRType> InvokeArgs;

		protected IRInvokeSig(string mn, List<IRType> st)
		{
			this.InvokeName = mn;
			this.InvokeArgs = st;
		}

		public string StringifyNameAndArgList()
		{
			StringBuilder sb = new StringBuilder(this.InvokeName + "(");
			for(int i = 0; i < this.InvokeArgs.Count; ++i)
			{
				if(i != 0)
					sb.Append(",");

				sb.Append(this.InvokeArgs[i].ToString());
			}
			sb.Append(")");
			return sb.ToString();
		}

		public bool IsConstructor { get { return this.InvokeName.Equals(".ctor"); } }
	}


	/// <summary>
	/// Class which represents static invocation signatures.
	/// </summary>
	public sealed class IRStaticInvoke : IRInvokeSig
	{
		/// <summary>
		/// Get the class which defines this static method.
		/// </summary>
		public readonly IRType DefClass;

		internal IRStaticInvoke(IRType defcl, string name, List<IRType> sigt)
			: base(name, sigt)
		{ this.DefClass = defcl; }

		public override string ToString()
		{ return this.DefClass.ToString() + "." + this.StringifyNameAndArgList(); }
	}

	public sealed class IRVirtualInvoke : IRInvokeSig
	{
		internal IRVirtualInvoke(string name, List<IRType> sigt)
			: base(name, sigt)
		{ ;}

		public override string ToString()
		{ return this.StringifyNameAndArgList(); }
	}

	/// <summary>
	/// Class which represents member invocation signatures.
	/// </summary>
	public sealed class IRInvokeIdentity
	{
		/// <summary>
		/// The class where the invoke is defined.
		/// </summary>
		public readonly IRType DefInClass;

		/// <summary>
		/// The signature of the method.
		/// </summary>
		public readonly IRInvokeSig InvSig;

		/// <summary>
		/// An integer which we will use to ensure a stable order on the invoke identities and enable tracking.
		/// Only valid within a single run!!!
		/// </summary>
		public int InvIDStableKey;

		internal IRInvokeIdentity(IRType tt, IRInvokeSig invs)
		{
			this.DefInClass = tt;
			this.InvSig = invs;
			this.InvIDStableKey = -1;
		}

		public override string ToString()
		{
			if(this.InvSig is IRStaticInvoke)
				return this.InvSig.ToString();
			else
				return this.DefInClass.ToString() + "::" + this.InvSig.ToString();
		}

		/// <summary>
		/// Compute and order on the invoke ids based on their string name order to ensure stable sorting later.
		/// </summary>
		internal static void ComputeInvokeIDStableOrder(List<IRInvokeIdentity> iidl)
		{
			iidl.Sort((IRInvokeIdentity iidl1, IRInvokeIdentity iidl2) => iidl1.ToString().CompareTo(iidl2.ToString()));

			for(int i = 0; i < iidl.Count; ++i)
				iidl[i].InvIDStableKey = i;
		}

		/// <summary>
		/// Order the invoke identifiers based on the stable ids (which are the lexo-sort order of the full names at load time).
		/// </summary>
		public static int ComputeInvokeCompareByName(IRInvokeIdentity ii1, IRInvokeIdentity ii2)
		{ return (ii1.InvIDStableKey - ii2.InvIDStableKey); }
	}
}
